#pragma once
#include <string>
#include <vector>
#include "../mqcommon/Helper.hpp"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/mq_msg.pb.h"

namespace mq_zxws
{
    class Router{
    public:
        static bool isLegalRoutine(const std::string& routine){
            for(auto& e : routine){
                if(isdigit(e) || isalpha(e) || e == '.' || e == '_')
                    continue;
                return false;
            }
            return true;
        }
        static bool isLegalBinding(const std::string& binding){
            for(auto& e : binding){
                if(isdigit(e) || isalpha(e) || e == '.' || e == '_' || e == '*' || e == '#')
                    continue;
                return false;
            }

            std::vector<std::string> sub_words;
            StrHelper::splite(binding, ".", sub_words);
            for(auto & word : sub_words){
                if(word.size() >  1 && (word.find('*') != std::string::npos || word.find('#') != std::string::npos))
                    return false;
            }
            for(int i = 1; i < sub_words.size(); i++){
                if(sub_words[i] == "#" && (sub_words[i - 1] == "#" || sub_words[i - 1] == "*"))
                    return false;
                if(sub_words[i] == "*" && sub_words[i - 1] == "#")
                    return false;
            }
            return true;
        }
        static bool route(ExchangeType mode, const std::string& routine, const std::string& binding){
            if(mode == ExchangeType::DIRECT) return routine == binding;
            else if(mode == ExchangeType::FANOUT) return true;
            std::vector<std::string> s, t;
            StrHelper::splite(binding, ".", s);
            StrHelper::splite(routine, ".", t);
            // dp[i][j] 表示前i个字符串和前j个字符串匹配
            // dp[i][j] =  dp[i-1][j-1] (s[i] == t[j])
            // dp[i][j] =  (s[i] != t[j]) 
            //             s[i] == "*" dp[i-1][j-1] 
            //             s[i] == "#" dp[i-1][j] || dp[i-1][j-1] || dp[i-1][j-2]...
            //                     <=> dp[i-1][j] || dp[i][j-1]
            DLOG("mode : %d  routine: %s  binding: %s", mode, routine.c_str(), binding.c_str());
            int n = s.size(), m = t.size();
            std::vector<std::vector<bool>> f(n+1, std::vector<bool>(m+1));
            f[0][0] = true;
            for(int i = 1; i <= n; i++){
                if(s[i-1] != "#") break;
                f[i][0] = true;
            }
            for(int i = 0; i < n; i++){
                for(int j = 0; j < m; j++){
                    if(s[i] == t[j] || s[i] == "*") f[i+1][j+1] = f[i][j];
                    else if(s[i] == "#") f[i+1][j+1] = f[i][j] | f[i][j+1] | f[i+1][j];
                }
            }
            return f.back().back();
        }
    };
}